package org.lgiavedoni.android.franq.core.listener;

import org.lgiavedoni.android.franq.service.config.ConfigService;
import org.lgiavedoni.android.franq.service.config.ConfigService.ConfigKey;
import org.lgiavedoni.android.franq.service.log.Logger;
import org.lgiavedoni.android.franq.service.phone.ContextService;
import org.lgiavedoni.android.franq.util.thread.ThreadUtil;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

public abstract class PhoneSensorEventListener implements PhoneListener, SensorEventListener {

	private static SensorManager mSensorMgr;
	private Boolean listening = false;

	protected PhoneSensorEventListener() {
		if (ContextService.inst.getApplicationContext() != null && mSensorMgr == null)
			mSensorMgr = (SensorManager) ContextService.inst.getApplicationContext().getSystemService(Context.SENSOR_SERVICE);
	}

	public synchronized void registerListener() {
		if (ContextService.inst.getApplicationContext() == null)
			return;
		if (listening)
			return;

		Logger.inst.info("Registering Listener [" + getClass().getName() + "]");

		if (mSensorMgr == null) {
			Logger.inst.error("Sensors not supported");
			return;
		}
		boolean supported = mSensorMgr.registerListener(this, mSensorMgr.getDefaultSensor(getSensorType()), getRate());
		if (!supported) {
			unregisterListener();
			Logger.inst.error("Accelerometer not supported");
		} else {
			// In some cases when the sensor is registered start sending events.
			// For that we wait until is really working
			new Thread() {
				@Override
				public void run() {
					ThreadUtil.sleep(7000);
					listening = true;
				}
			}.start();
		}
	}

	public synchronized void unregisterListener() {
		listening = false;
		Logger.inst.info("Unregistering Listener [" + getClass().getName() + "]");
		if (mSensorMgr != null) {
			mSensorMgr.unregisterListener(this, mSensorMgr.getDefaultSensor(getSensorType()));
		}
	}

	private class Register extends Thread {
		@Override
		public void run() {
			setName("Sensor Register[SensorType:" + getSensorType() + ", Wakeup: " + ThreadUtil.wakeUp(ConfigService.inst.getValueAsLong(ConfigKey.SENSOR_LISTENER_DISABLE_PERIOD))
					+ "]");
			ThreadUtil.sleep(ConfigService.inst.getValueAsLong(ConfigKey.SENSOR_LISTENER_DISABLE_PERIOD));
			registerListener();
		}
	}

	public int getRate() {
		return SensorManager.SENSOR_DELAY_NORMAL;
	}

	public abstract int getSensorType();

	public final synchronized void onSensorChanged(SensorEvent sEvent) {
		// Ignore the default event
		if (sEvent.timestamp == 0)
			return;

		if (isListening()) {
			// Unregister listener
			unregisterListener();
			new Register().start();
			// Throw the event
			_onSensorChanged(sEvent);
		}
	}

	public abstract void _onSensorChanged(SensorEvent sEvent);

	@Override
	public void onAccuracyChanged(Sensor s, int arg1) {
		// Do nothing
	}

	public boolean isListening() {
		return listening;
	}

}
